#include "tomosim.h"

TomoSim::TomoSim(QWidget *parent) :
        QMainWindow(parent), num_cameras_(3), p_dist_(NULL), sigma_x_(3), sigma_y_(3), A_(1), log_(false), draw_tank_(false), ren_image_(false), camera_changed_(false) {
    ui.setupUi(this);
    QList<int> list, list1;
    list << 800 << 400;
    list1 << 200 << 600;
    ui.splitter->setSizes(list);
    ui.splitter_2->setSizes(list1);

    QFileSystemModel* fmodel = new QFileSystemModel(parent);
    fmodel->setRootPath(QDir::currentPath());
    ui.treeView->setModel(fmodel);
    ui.treeView->setRootIndex(fmodel->index(QDir::currentPath()));
    renwin_ = ui.qvtkWidget->GetRenderWindow();

    //camera_pos_ << Point3D<float> (5.0, 0.0, 0.0) << Point3D<float> (0.0, 5.0,
    //		0.0) << Point3D<float> (0.0, 0.0, 5.0);
    renderer_ = vtkSmartPointer<vtkRenderer>::New();
    vtkSmartPointer < vtkRenderWindow > renWin
            = renwin_; //vtkSmartPointer<vtkRenderWindow>::New();
    renWin->AddRenderer(renderer_);

    renderer_->SetBackground(0, 0, 0);
    //renWin->SetSize(800, 400);
    vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
    cube->SetCenter(0,0,0);
    cube->SetXLength(4);
    cube->SetYLength(4);
    cube->SetZLength(2);

    vtkSmartPointer<vtkPolyDataMapper> cubeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    cubeMapper->SetInputConnection(cube->GetOutputPort());
    tank_ = vtkSmartPointer<vtkActor>::New();
    tank_->SetMapper(cubeMapper);
    tank_->GetProperty()->SetEdgeVisibility(true);
    tank_->GetProperty()->SetEdgeColor(1,1,1);
    tank_->GetProperty()->SetOpacity(0.5);
    tank_->GetProperty()->SetColor(1,1,1);

    if(draw_tank_)
        renderer_->AddActor(tank_);
    // Set up the lighting.
    //
    light_ = vtkSmartPointer<vtkLight>::New();
    light_->SetFocalPoint(0, 0, 0);
    light_->SetPosition(0, 2, 0);
    light_->SetIntensity(ui.spbLightIntensity->value());
    renderer_->AddLight(light_);

    // We want to eliminate perspective effects on the apparent lighting.
    // Parallel camera projection will be used. To zoom in parallel projection
    // mode, the ParallelScale is set.
    //
    renderer_->GetActiveCamera()->SetFocalPoint(0, 0, 0);
    renderer_->GetActiveCamera()->SetPosition(0, 0, 6);
    //renderer_->GetActiveCamera()->SetViewUp(0, 1, 0);
    renderer_->GetActiveCamera()->ParallelProjectionOff();
    //renderer_->ResetCamera();
    //renderer_->GetActiveCamera()->SetParallelScale(1);
    cameras_.append(renderer_->GetActiveCamera());

    vtkSmartPointer<vtkCamera> cam2 = vtkSmartPointer<vtkCamera>::New();
    cam2->SetPosition(5.2,0,3);
    cam2->SetFocalPoint(0,0,0);
    cam2->ParallelProjectionOff();
    //cam2->SetParallelScale(1);

    cameras_.append(cam2);

    vtkSmartPointer<vtkCamera> cam3 = vtkSmartPointer<vtkCamera>::New();
    cam3->SetPosition(-5.2,0,3);
    cam3->SetFocalPoint(0, 0, 0);
    cam3->ParallelProjectionOff();
    //cam3->SetParallelScale(1);
    cameras_.append(cam3);

    graphics_factory_ = vtkSmartPointer<vtkGraphicsFactory>::New();
    graphics_factory_->SetOffScreenOnlyMode( 1);
    graphics_factory_->SetUseMesaClasses( 1 );

    imaging_factory_ = vtkSmartPointer<vtkImagingFactory>::New();
    imaging_factory_->SetUseMesaClasses( 1 );
}

TomoSim::~TomoSim() {

}

void TomoSim::on_actionOpen_File_triggered() {
    QFileDialog fdialog(this);
    fdialog.setAcceptMode(QFileDialog::AcceptOpen);
    fdialog.setFileMode(QFileDialog::ExistingFiles);
    fdialog.setViewMode(QFileDialog::Detail);
    QStringList fileNames;
    if (fdialog.exec())
        fileNames = fdialog.getOpenFileNames();
    //one data file is selected, treat it as the 3D coordination file.

    if (fileNames.length() == 1) {
        p_dist_ = new ParticleDistribution(fileNames[0],
                                           ui.spbNumParticles->value());
    }
}

void TomoSim::on_actionExit_triggered() {
    this->close();
}

void TomoSim::on_pushButton_clicked() {

    QModelIndexList flist = ui.treeView->selectionModel()->selectedIndexes();

    if (flist.length()>1){
        if(p_dist_!=NULL)
            delete p_dist_;
        QString fname = ((QFileSystemModel*)ui.treeView->model())->filePath(flist[0]);
        p_dist_ = new ParticleDistribution(fname,ui.spbNumParticles->value());
    }

    if(camera_changed_){
        QString str = ui.ledCamPos->text();
        QStringList strlist = str.split('*');
        for(int i=0;i<strlist.length();i++){
            QStringList strlist1 = strlist.at(i).split(' ');
            cameras_[i]->SetPosition(strlist1[0].toDouble(),strlist1[1].toDouble(),strlist1[2].toDouble());
        }
    }

    light_->SetIntensity(ui.spbLightIntensity->value());
    // The following lines create a sphere represented by polygons.
    //
    vtkSmartPointer < vtkSphereSource > sphere = vtkSmartPointer<
                                                 vtkSphereSource>::New();
    sphere->SetThetaResolution(100);
    sphere->SetPhiResolution(50);
    sphere->SetRadius(0.01);

    vtkSmartPointer < vtkPolyDataMapper > sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    sphereMapper->SetInputConnection(sphere->GetOutputPort());

    if(p_dist_!=NULL)
	for (int i = 0; i < this->p_dist_->NumParticles(); i++) {
        vtkSmartPointer < vtkActor > sphere1 = vtkSmartPointer<vtkActor>::New();
        sphere1->SetMapper(sphereMapper);
        //float intensity = exp( - ((*p_dist_)[i].Z()*(*p_dist_)[i].Z() + (*p_dist_)[i].X()*(*p_dist_)[i].X())/(sigmal_*sigmal_));
        float intensity  = A_*exp( - ( pow((*p_dist_)[i].X() ,2)/(2*sigma_x_*sigma_x_) +  pow((*p_dist_)[i].Y() ,2)/(2*sigma_y_*sigma_y_)));
        if(log_)
            std::cout << "Particle(" << (*p_dist_)[i].X() << "," <<(*p_dist_)[i].Y()<< ","<<(*p_dist_)[i].Z() << ") Intensity "<< intensity << std::endl;
        sphere1->GetProperty()->SetColor(intensity, intensity, intensity);
        sphere1->SetPosition((*p_dist_)[i].X(),(*p_dist_)[i].Y(),(*p_dist_)[i].Z());
        //sphere1->GetProperty()->SetAmbient(0.3);
        //sphere1->GetProperty()->SetDiffuse(0.0);
        //sphere1->GetProperty()->SetSpecular(1.0);
        //sphere1->GetProperty()->SetSpecularPower(5.0);
        // Add the actors to the renderer, set the background and size.
        //
        renderer_->AddActor(sphere1);
    }
    renwin_->Render();

    if(ren_image_){
        vtkSmartPointer<vtkCamera> tempCamera = renderer_->GetActiveCamera();
        for(int i=0;i<num_cameras_;i++){
            renderer_->SetActiveCamera(cameras_[i]);
            renwin_->Render();

            vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter =
                    vtkSmartPointer<vtkWindowToImageFilter>::New();
            windowToImageFilter->SetInput(renwin_);
            windowToImageFilter->Update();

            vtkSmartPointer<vtkPNGWriter> writer =
                    vtkSmartPointer<vtkPNGWriter>::New();
            QString outname = QString("camera_%1.png").arg(i);
            QByteArray arr = outname.toLocal8Bit();
            const char* cname = arr.data();
            writer->SetFileName(cname);
            writer->SetInput(windowToImageFilter->GetOutput());
            writer->Write();
        }
        renderer_->SetActiveCamera(tempCamera);
        renwin_->Render();
    }
}

void TomoSim::on_comboBox_currentIndexChanged(int index){
    renderer_->SetActiveCamera(cameras_[index]);
    renwin_->Render();
}

void TomoSim::on_pushButton_2_clicked(){
    renderer_->RemoveAllViewProps();
    if(draw_tank_)
        renderer_->AddActor(tank_);
    renwin_->Render();
}

void TomoSim::on_chbRenderToImage_stateChanged(int state){
    // Setup offscreen rendering
    if(state){
        graphics_factory_->SetOffScreenOnlyMode( 1);
        graphics_factory_->SetUseMesaClasses( 1 );
        imaging_factory_->SetUseMesaClasses( 1 );
    }else{
        graphics_factory_->SetOffScreenOnlyMode( 0);
        graphics_factory_->SetUseMesaClasses( 0 );
        imaging_factory_->SetUseMesaClasses( 0 );
    }

    ren_image_ = state;
}

void TomoSim::on_chbUseLog_stateChanged(int state){
    log_ = state;
}

void TomoSim::on_spbNumCameras_valueChanged(int value){
    num_cameras_=value;
}
